﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Drawing;

namespace DirectX_CS
{
	class Cartesian3dAxis : IManagedVertexBuffer, IManagedModelTransformable, IManagedMaterial, IColorable, IRangeModifiable, IDisposable
	{
		[PGBrowsable]
		public Range3d Range
		{
			get { return new Range3d(XMin, YMin, ZMin, XMax, YMax, ZMax); }
		}
		public event VBChangedDelegate VertexBufferChanged;

		protected PrimitiveManager renderer = null; //main memory manager..change name.
		protected Device mDevice = null;
		protected SVector[] vertexData = null;

		[PGBrowsable]
		public VertexFormats VertexFormat
		{
			get { return SVector.Format; }
		}
       // private System.Drawing.Font mFont = null;
       // private Sprite shh;
       // private Microsoft.DirectX.Direct3D.Font mDXFont;	
		[PGBrowsable]
		public Color MainVertexColor {
			set
			{
				mMainColor = value;
				Recreate();
			}
			get
			{
				return mMainColor;
			}
		}
		private TransformMatrix vTransform = new TransformMatrix();
		[PGBrowsable]
		public TransformMatrix ModelView
		{
			get { return vTransform; }
			set { vTransform = value; }
		}

        public float xMin = -10, xMax = 10;
		[PGBrowsable]
        public float XMax
        {
            get { return xMax; }
            set
            {
                xMax = value; 
            }
        }
		[PGBrowsable]
        public float XMin
        {
            get { return xMin; }
            set
            {
                xMin = value; 
            }
        }
        public float yMin = -10, yMax = 10;
		[PGBrowsable]
        public float YMax
        {
            get { return yMax; }
            set
            {
                yMax = value; 
            }
        }
		[PGBrowsable]
        public float YMin
        {
            get { return yMin; }
            set
            {
                yMin = value;
            }
        }
        public float zMin = -10, zMax = 10;
		[PGBrowsable]
        public float ZMax
        {
            get { return zMax; }
            set
            {
                zMax = value; 
            }
        }
		[PGBrowsable]
        public float ZMin
        {
            get { return zMin; }
            set
            {
                zMin = value; 
            }
        }

        private int divisionsX = 20;
		[PGBrowsable]
        public int DivisionsX
        {
            get { return divisionsX; }
            set
            {
                divisionsX = value;
            }
        }
        private int divisionsY = 20;
		[PGBrowsable]
        public int DivisionsY
        {
            get { return divisionsY; }
            set
            {
                divisionsY = value;
            }
        }
        private int divisionsZ = 20;
		[PGBrowsable]
        public int DivisionsZ
        {
            get { return divisionsZ; }
            set
            {
                divisionsZ = value;
            }
        }

        private Material mMaterial;
		private Color mMainColor = Color.DarkRed;
		[PGBrowsable]
        public Material Material
        {
			get { return mMaterial; }
			set { mMaterial = value; }
        }

        protected void InitializeMaterial()
        {
            mMaterial = new Material();
			//mMaterial.Emissive = Color.DarkBlue;
			mMaterial.Specular = Color.FromArgb(122, 255, 255, 255);
			mMaterial.Ambient = Color.FromArgb(122, 255, 255, 255);// Color.FromArgb(255, Color.GreenYellow); 
            mMaterial.Diffuse = Color.FromArgb(122,255, 255, 255); 
        }

        public Cartesian3dAxis(float xmin, float xmax, float ymin, float ymax, float zmin, float zmax, int divisionsx, int divisionsy, int divisionsz)       // private Sprite shh;
        {
            mDevice = MainProgram.DxDevice; //set before registering for sure...
            InitializeMaterial();

            xMax = xmax;
            xMin = xmin;
            yMax = ymax;
            yMin = ymin;
            zMax = zmax;
            zMin = zmin;
            divisionsX = divisionsx;
            divisionsY = divisionsy;
            divisionsZ = divisionsz;
            /*mFont = axisLabelFont;
            if (mFont == null)
                mFont = new System.Drawing.Font(FontFamily.GenericSerif, 12, GraphicsUnit.World);

            mDXFont = new Microsoft.DirectX.Direct3D.Font(device, mFont);
            mDXFont.Lost += new EventHandler(mDXFont_Lost);
            position = new Vector3(0, 0, 0);
            shh = new Sprite(mDevice);
             */

            vertexData = CreateHeightData();
            renderer = PrimitiveManager.OnlyManager;

            PrimitiveManager.Register( this );
            if (VertexBufferChanged != null)
                VertexBufferChanged( this, vertexData.Length );
        }
		/// <summary>
		/// BEGINNING OF IMPLEMENTATION of the interface..
		/// </summary>

		/// <summary>
		/// Careful because registering the primitiveWithVertices generator allocates memory for the primitives it generates, 
		/// and sometimes(depending on the settings) attempts to render the objects in its registered list.
		/// </summary>
        public Cartesian3dAxis()       // private Sprite shh;
		{
			mDevice = MainProgram.DxDevice; //set before registering for sure...
            InitializeMaterial();

			vertexData =  CreateHeightData();
			renderer = PrimitiveManager.OnlyManager;

			PrimitiveManager.Register(this);
			VertexBufferChanged(this, vertexData.Length);
		}
        /***
		void mDXFont_Lost(object sender, EventArgs epsilon)
		{
			mDXFont = null;
		}
        */
		public void Recreate()
		{
			vertexData = CreateHeightData();
			if (VertexBufferChanged != null)
				VertexBufferChanged(this, vertexData.Length);
		}
		public void UpdateTransform()
		{
			VertexBufferChanged(this, vertexData.Length);
		}
		~Cartesian3dAxis()
		{
			DisposeInstance();
		}

		public void DisposeInstance()
		{
			if (renderer != null)
				renderer.UnregisterPrimitive(this); //cannot hurt to unregister.
			//mDXFont = null;
			//mFont = null;
			//shh = null;
		}
		
		public Array GetVertices()
		{
			return (Array)vertexData;
		}
		
		public int GetVerticesCount()
		{
			return vertexData.Length;
		}
		protected bool mEnableCallRenderPrimitives = true;
		[PGBrowsable]
		public bool EnableCallRenderPrimitives
		{
			get { return mEnableCallRenderPrimitives; }
			set { mEnableCallRenderPrimitives = value; }
		}

		/// <summary>
		/// Since each primitiveWithVertices should for diversity be in charge of its own representation
		/// in rendering, although the memory will be managed.
		/// </summary>
		public void RenderPrimitives(PrimitiveManager caller, int dataLength)
		{
            int numPrimitives = (int)(dataLength / 2);
			mDevice.DrawPrimitives(PrimitiveType.LineList, 0, numPrimitives); 
            /*			
             * // Unsolved problem with drawing text.
			//Matrix positionMatrix = Matrix.Multiply(tform, Matrix.Translation());
			//Matrix pm = new Matrix(); //point matrix
			//pm = Matrix.Zero;
			//pm.M11 = (XMax-XMin)/3; pm.M12 = 0; pm.M13 = 0; pm.M14 = 0;
			//pm.M21 = 0; pm.M22 = (YMax - YMin) / 3; pm.M23 = 0; pm.M24 = 0;
			//pm.M31 = 0; pm.M32 = 0; pm.M33 = ZMax - ZMin; pm.M34 = 0;
			//pm.M41 = 0; pm.M42 = 0; pm.M43 = 0; pm.M44 = 0;

			//Matrix result = Matrix.Multiply(tform, pm);
			//Point pnt0 = new Point((int)result.M11, (int)result.M21);
			//Point pnt1 = new Point((int)result.M12, (int)result.M22);
			//Matrix m = mDevice.Transform.View.Multiply(Matrix.Translation(new Vector3(YMax - YMin, 0, 0)));
			//Point pnt1 = (m.M11, m.M22);
			//Point pnt2 = 
			//DrawText("X axis", new Vector3(xMax-XMin,0,0), pnt0 );
			//DrawText("Y axis", new Vector3(0,YMax-YMin,0), pnt1);
			//DrawText("Z axis", new Vector3(0, 0, ZMax - ZMin), pnt2);
			

			//shh.SetWorldViewLH(mDevice.Transform.World, mDevice.Transform.View); //optional?

			Matrix textPositionMatrix = positionMatrix;
			shh.Begin(SpriteFlags.ObjectSpace);
			
			
			//textPositionMatrix.Translate((XMax - XMin) / 2, 0, 0);
			shh.Transform = mDevice.Transform.World;//textPositionMatrix;
			
			///Point drawPoint = new Point(10,10);
			string theString = "X";
			Rectangle rnd = mDXFont.MeasureString(null, theString, DrawTextFormat.NoClip , Color.Salmon);

			rnd.Width = 100;//rnd.Width / 2;
			rnd.Height = 100;//rnd.Height / 2;
			rnd.Location = new Point(100,100);
            shh.End(); 
			mDXFont.DrawText(null, theString, rnd, DrawTextFormat.NoClip, Color.Salmon);
            */
		}

		Array GetIndices()
		{
			return null;
		}

		public void ManagerDestroyed(PrimitiveManager caller)
		{
			//signals to registered primitiveWithVertices generator that renderer is or has been destroyed
			//so we should stop sending messages or at least relaying them to the renderer
			renderer = null;
			
            //mDXFont = null;
			//mFont = null;
			//shh = null;
		}
		/// <summary>
		/// End of required implementation;
		/// </summary>
		/// 
		float tickLenX = .2f;

		[PGBrowsable]
		public float TickLenX
		{
			get { return tickLenX; }
            set
            {
                tickLenX = value; 
            }
		}
		float tickLenY = .2f;
		[PGBrowsable]
		public float TickLenY
		{
			get { return tickLenY; }
            set
            {
                tickLenY = value; 
            }
		}
		float tickLenZ = .2f;
		[PGBrowsable]
		public float TickLenZ
		{
			get { return tickLenZ; }
            set
            {
                tickLenZ = value; 
            }
		}

        Color color0 = Color.FromArgb(0, Color.DarkRed);
		[PGBrowsable]
		public Color Color0
		{
			get { return color0; }
			set { color0 = value;}
		}
		Color color1 = Color.FromArgb(0, Color.DarkGreen);
		[PGBrowsable]
        public Color Color1
		{
			get { return color1; }
			set { color1 = value; }
		}
        Color color2 = Color.FromArgb(0, Color.DarkOrange);
		[PGBrowsable]
        public Color Color2
		{
			get { return color2; }
			set { color2 = value; }
		}

/// <summary>
/// Create the height data vertex by vertex.
/// </summary>
/// 
public SVector[] CreateHeightData()
{
	int pIdx = 0; //point index
	float dx, dy, dz;

    int xCount = divisionsX+1;
    int yCount = divisionsY+1;
    int zCount = divisionsZ+1;
	SVector[] LineList = new SVector[6+ (4*xCount + 4*yCount + 6*zCount) + 2*xCount + 1*yCount + 2*zCount]; //3 for each axis two for each line

    LineList[pIdx++] = new SVector(xMin, 0, 0, mMainColor);
	LineList[pIdx++] = new SVector(xMax, 0, 0, mMainColor);

	LineList[pIdx++] = new SVector(0, yMin, 0, mMainColor);
	LineList[pIdx++] = new SVector(0, yMax, 0, mMainColor);


	LineList[pIdx++] = new SVector(0, 0, zMin, mMainColor);
	LineList[pIdx++] = new SVector(0, 0, zMax, mMainColor);

	dx = (xMax - xMin) / divisionsX;
	for (float x = xMin; x <= xMax; x += dx)
	{
		LineList[pIdx++] = new SVector(x, 0, 0,  Color1);
		LineList[pIdx++] = new SVector(x, tickLenY, 0, Color1);
	}
	dy = (yMax - yMin) / divisionsY;
	for (float y = yMin; y <= yMax; y += dy)
	{
		LineList[pIdx++] = new SVector(tickLenX, y, 0,  Color1);
		LineList[pIdx++] = new SVector(0, y, 0,  Color1);
	}
	dz = (zMax - zMin) / divisionsZ;
	for (float z = zMin; z <= zMax; z += dz)
	{
		LineList[pIdx++] = new SVector(tickLenZ, 0, z,  Color1);
		LineList[pIdx++] = new SVector(0, 0, z, Color1);
	}

	//DZX
	dx = (xMax - xMin) / divisionsX;
	for (float x = xMin; x <= xMax; x += dx)
	{
		LineList[pIdx++] = new SVector(x, 0, tickLenZ,  Color1);
		LineList[pIdx++] = new SVector(x, 0, 0, Color1);
	}

	dz = (zMax - zMin) / divisionsZ;
	for (float z = zMin; z <= zMax; z += dz)
	{
		LineList[pIdx++] = new SVector(tickLenX, 0, z, Color2);
		LineList[pIdx++] = new SVector(0, 0, z, Color2);
	}

	//DZY
	dz = (zMax - zMin) / divisionsZ;
	for (float z = zMin; z <= zMax; z += dz)
	{
		LineList[pIdx++] = new SVector(0, tickLenY, z, Color2);
		LineList[pIdx++] = new SVector(0, 0, z, Color2);
	}
	dy = (yMax - yMin) / divisionsY;
	for (float y = yMin; y <= yMax; y += dy)
	{
		LineList[pIdx++] = new SVector(0, y, tickLenZ,Color1);
		LineList[pIdx++] = new SVector(0, y, 0, Color1);
	}


    //float lineWidth = XMax - XMin;
    //float lineHeight = YMax - YMin;
    //dy = (lineWidth) / DivisionsY;
    // dx = (lineHeight) / DivisionsX;

    for (float y = yMin; y <= yMax; y += dy)
    {
		LineList[pIdx++] = new SVector(xMin, y, 0, Color1);
		LineList[pIdx++] = new SVector(xMax, y, 0, Color1);
    }
    for (float x = xMin; x <= xMax; x += dx)
    {
		LineList[pIdx++] = new SVector(x, yMin, 0, Color1);
		LineList[pIdx++] = new SVector(x, yMax, 0, Color1);
    }
    /*
    //float dz = ZMax - ZMin;
    for (float z = ZMin; z <= ZMax; z += dz)
    {
        LineList[pIdx++] = new SVector( XMin, 0, z, DarkGreen );
        LineList[pIdx++] = new SVector( XMax, 0, z, DarkGreen );
    }
     */
    //for (float y = YMin; y <= YMax; y += dy)
    //{
    //    LineList[pIdx++] = new SVector( XMin, y, z, DarkGreen );
    //    LineList[pIdx++] = new SVector( XMax, y, z, DarkGreen );
    //}


    return LineList;

}


	}//end of class..
}//end of namespace.
